﻿// ## 2023/11/06 # 铃 # 精简多个触发器,减少计算量,减少计算范围,优化逻辑##
// ## 2023/03/02 # 铃 # 继续汉化注释和常量,优化逻辑和代码##
// ## 2022/03/04 # 铃 # 有些战斗部队的策略没有排除撤退部队.增加对撤退部队的排除##
// ## 2022/02/19 # 铃 # 剩下常量中文化  注释中文化##
// ## 2022/02/14 # 江东新风 # 部分常量中文化 ##
// ## 2021/12/02 #江东新风#变量汉化##
// ## 2021/10/24 #江东新风#改写171trigger##
// ## 2020/12/12 #江东新风# 修复trace参数类型错误 ##
// ## 2020/12/05 # 江东新风 # 修复颜色乱码 ##
// ## 2020/11/20 # messi # 优化了部队选择目标语句 ##
// ## 2020/10/30 # 江东新风 # 同步马术书大神的更新 ##

namespace 野战部队交战优化
{
    //=======================================================================================


    const int 部队目标变更_势力条件 = 0;          // 0:电脑AI和player _委任军团，1:player _委任军团，2:电脑AI, 3:均未使用
    const bool 部队目标变更_适用玩家军团 = false; // 与势力条件无关，设定是否适用，忽略玩家的任务指定，建议false

    const float 进入部队_超过限度标准 = 1.0f;          // 据点最大兵力对比兵力/兵器(据点+部队)设定超过限度标准(0.0f~1.0f)
    const float 进入部队_兵器超过_据点兵力标准 = 0.5f; // 相对据点最大兵力而言，目前兵力不足标准则忽略兵器超支(0.0 ~1.0f)。

    bool 调试模式 = false;
    bool 调试模式2 = false;
    bool 调试模式3 = false;
//=======================================================================================

    class Main
    {

        Main()
        {

            pk::bind(102, pk::trigger102_t(onGameInit));
            //pk::bind(111, pk::trigger111_t(onTurnStart));
            pk::bind(161, pk::trigger161_t(onBuildingDestroyed));
            pk::bind(166, pk::trigger166_t(onBuildingChange));
            pk::bind(171, pk::trigger171_t(onUnitEliminated));

        }
        //---------------------------------------------------------------------------

        pk::unit @src_unit;
        pk::unit @dst_unit_old;
        pk::unit @dst_unit_new;

        pk::list<pk::unit @> list_candidate_unit;
        pk::list<pk::building @> list_candidate_building;
        array<int> arr_target_unit_id(部队_末, -1);
        array<int> arr_target_base_id(部队_末, -1);

        array<float> heishu_weight(6, 0.0f);
        float heishu_null = 0.0f;
        float heishu_weak = 0.5f;
        float heishu_normal = 1.0f;
        float heishu_strong = 1.5f;
        int order_update_range = 6; // 创建/移除建筑物或创建/移除/移动时任务更新的部队搜索范围

        //---------------------------------------------------------------------------
        // 触发动作
        //---------------------------------------------------------------------------

        // 游戏初始化时更新
        void onGameInit()
        {
            if (pk::is_campaign())
                return;
            if (pk::get_scenario().no >= 16)
                return;
            clear_target_info();
            pk::force @force = pk::get_force(pk::get_current_turn_force_id());
            onTurnStart(force);
        }

        // 回合开始时更新
        void onTurnStart(pk::force @force)
        {
            if (pk::is_campaign())
                return;


            if (!pk::is_normal_force(force))
                return;
            optimize_current_force_target(); // 通用函数调用
        }


        // 破坏建筑时更新
        void onBuildingDestroyed(pk::building @building, int type)
        {
            if (pk::is_campaign())
                return;


            optimize_pos_range_target(building.pos); // 通用函数调用
        }

        // 据点转换势力时更新
        void onBuildingChange(pk::building @building, pk::force @force)
        {
            if (pk::is_campaign())
                return;


            optimize_pos_range_target(building.pos); // 通用函数调用
        }

        // 部队溃灭时候更新
        void onUnitEliminated(pk::unit @unit, pk::hex_object @dst, int type)
        {
        // 重置溃败部队的攻击目标
            arr_target_unit_id[unit.get_id()] = -1;
            arr_target_base_id[unit.get_id()] = -1;

            optimize_pos_range_target(unit.pos); // 通用函数调用
        }


        //---------------------------------------------------------------------------
        // 从基准坐标开始，优化当前回合势力部队在一定范围内的目标
        void optimize_pos_range_target(pk::point pos_t)
        {
            if (!pk::is_valid_pos(pos_t))
                return;
            int force_id = pk::get_current_turn_force_id();
            if (!pk::is_normal_force(force_id))
                return;
            pk::force @force = pk::get_force(force_id);
            // 从该坐标开始，搜索范围内的当前回合部队
            pk::array<pk::point> arr_range = pk::range(pos_t, 1, order_update_range);
            for (int i = 0; i < int(arr_range.length); i++)
            {
                pk::unit @unit = pk::get_unit(arr_range[i]);
                if (check_valid_unit(unit) and check_force_option(unit))
                {
                    if (!unit.action_done and unit.get_force_id() == force_id)
                        optimize_combat_unit_target(unit); // 重新设置部队目标的函数
                }
            }
        }
        // 优化当前回合势力部队的目标 (公共函数)
        void optimize_current_force_target()
        {
            int force_id = pk::get_current_turn_force_id();
            if (!pk::is_normal_force(force_id))
                return;
            pk::force @force = pk::get_force(force_id);

            pk::array<pk::unit @> arr_unit_list = pk::list_to_array(pk::get_unit_list());
            if (int(arr_unit_list.length) == 0)
                return;
            for (int i = 0; i < int(arr_unit_list.length); i++)
            {
                pk::unit @unit = arr_unit_list[i];
                if (check_valid_unit(unit) and check_force_option(unit))
                {
                    if (!unit.action_done and unit.get_force_id() == force_id)
                        optimize_combat_unit_target(unit); // 重新设置部队目标的函数
                }
            }
        }
        //---------------------------------------------------------------------------
        //---------------------------------------------------------------------------
        // 重新设置部队目标的函数
        void optimize_combat_unit_target(pk::unit @unit)
        {
            // 如果部队不存活，则结束
            if (!pk::is_alive(unit))
                return;

            if (调试模式3) pk::trace(pk::format("03{}部队, ", pk::decode(pk::get_name(unit))));
        // 获取目标部队
            @dst_unit_old = pk::hex_object_to_unit(pk::get_hex_object(unit.target_pos));
            // ------ 调用搜索可攻击敌方部队的函数 -------------
            // 注意：要先于 def_force_base_nearby、atk_enemy_base_nearby、retreat_exceed_unit 函数使用
            get_list_candidate_unit(unit);
            
            int candidate_count = list_candidate_unit.count;
            if (candidate_count == 0) // 如果部队是援军到达的情况，则在据点周围进行额外搜索
            {
                search_enemy_on_reinforce_engage(unit);
                candidate_count = list_candidate_unit.count;
            }

            if (调试模式3)  pk::trace(pk::format("04{}部队, ", pk::decode(pk::get_name(unit))));
            if (def_force_base_nearby(unit))
                return; // 支援周围正在战斗的友军据点
            if (调试模式3)  pk::trace(pk::format("05{}部队, ", pk::decode(pk::get_name(unit))));
            if (atk_enemy_base_nearby(unit))
                return; // 根据部队坐标判断是拦截/远征：如果是敌方远征，则设置为攻击据点
            if (调试模式3) pk::trace(pk::format("06{}部队, ", pk::decode(pk::get_name(unit))));
            if (retreat_exceed_unit(unit))
                return; // 如果兵力/兵器超过据点限制，则切换到其他据点路线
            if (调试模式3) pk::trace(pk::format("07{}部队, ", pk::decode(pk::get_name(unit))));


        }
        //---------------------------------------------------------------------------
        //---------------------------------------------------------------------------

         // 搜索可攻击敌方建筑的函数
        void get_list_candidate_building(pk::unit @unit)
        {
            // 初始化列表
            if (!pk::is_alive(unit))
                return;
            list_candidate_building.clear();
            int weapon_id = unit.weapon;
            int weapon_type = get_weapon_type(weapon_id); // 0:剑, 1:战斗, 2:冲车, 3:井阑, 4:水军 5:大船

            pk::array<pk::point> arr_t = pk::range(unit.pos, 1, 10);
            for (int j = 0; j < int(arr_t.length); j++)
            {
                pk::hex @hex = pk::get_hex(arr_t[j]);
                if (hex.has_building)
                {
                    pk::building @target_building = pk::get_building(arr_t[j]);
                    if (target_building !is null and pk::is_alive(target_building) and (pk::is_enemy(unit, target_building) or (target_building.facility < 设施_阵 and target_building.get_force_id() == -1)))
                    {
                        list_candidate_building.add(target_building); // 如果敌方部队可攻击，则添加到列表中
                    }
                }
            }
        }


    // 搜索可攻击敌方部队的函数
        void get_list_candidate_unit(pk::unit @unit)
        {
            // 初始化列表
            if (!pk::is_alive(unit))
                return;
            list_candidate_unit.clear();
            int weapon_id = unit.weapon;
            int weapon_type = get_weapon_type(weapon_id); // 0:剑, 1:战斗, 2:冲车, 3:攻城其他, 4:水军
            // 冲车不作为搜索目标
            if (weapon_id == 兵器_冲车)
                return;

            // 设置攻击范围 --- 函数修改 ('20.9.13)
            pk::int_int atk_range = get_atk_range(unit);
            int min = (weapon_id == 兵器_冲车) ? 0 : atk_range.first;
            int max = (weapon_id == 兵器_冲车) ? 0 : atk_range.second;
            pk::array<pk::point> range = pk::get_movable_pos(unit); // 可移动坐标
            for (int i = 0; i < int(range.length); i++)
            {
                pk::point pos = range[i];
                pk::hex @hex = pk::get_hex(pos);
                pk::array<pk::point> arr_t = pk::range(pos, min, max); // 周围坐标
                for (int j = 0; j < int(arr_t.length); j++)
                {
                    pk::unit @target_unit = pk::get_unit(arr_t[j]);
                    if (!hex.has_building and !hex.has_unit and pk::is_alive(target_unit) and pk::is_enemy(unit, target_unit) and !list_candidate_unit.contains(target_unit))
                    {
                        list_candidate_unit.add(target_unit); // 如果敌方部队可攻击，则添加到列表中
                    }
                }
            }
        }

        // 如果部队任务是前往重要据点，额外确认周围是否有敌方部队
        void search_enemy_on_reinforce_engage(pk::unit @unit)
        {
            if (!pk::is_alive(unit))
                return;
            if (list_candidate_unit.count > 0)
                return;
            if (unit.type != 部队类型_战斗)
                return;
            if (unit.weapon > 兵器_战马)
                return;
            pk::building @service_base = pk::get_building(pk::get_service(unit));
            if (!pk::is_alive(service_base))
                return;
            pk::building @base_p = pk::get_building(pk::get_building_id(unit.pos));
            if (!pk::is_alive(base_p))
                return;
            int service_id = service_base.get_id();
            int base_p_id = base_p.get_id();
            if (base_p_id == service_id or unit.get_force_id() != base_p.get_force_id())
                return; // 如果是所属据点领土或者是其他势力的领土
            if (unit.target_type == 部队任务对象_据点)
            {
                pk::building @base_t = pk::get_building(unit.target);
                if (pk::is_alive(base_t))
                {
                    int base_t_id = base_t.get_id();
                    // 如果目标据点与部队所在据点相同，或者目标据点在部队移动范围内
                    if (base_t_id < 据点_末 and (base_t_id == base_p_id or check_base_in_movable_range(unit, base_t)))
                    {
                        pk::array<pk::point> range = pk::range(base_p.pos, 1, 12); // 搜索据点周围
                        for (int i = 0; i < int(range.length); i++)
                        {
                            pk::point pos_i = range[i];
                            pk::unit @unit_i = pk::get_unit(pos_i);
                            if (pk::is_alive(unit_i) and pk::get_building_id(pos_i) == base_p_id and pk::is_enemy(unit, unit_i) and !list_candidate_unit.contains(unit_i))
                            {
                                list_candidate_unit.add(unit_i); // 如果敌方部队可攻击，则添加到列表中
                            }
                        }
                    }
                }
            }
        }
        //---------------------------------------------------------------------------
        //---------------------------------------------------------------------------
        // 攻击部队：确认当前坐标区域的据点势力：true=远征或援军/false=拦截判断
        bool atk_enemy_base_nearby(pk::unit @unit)
        {
            if (!pk::is_alive(unit))
                return false;
            if (unit.type != 部队类型_战斗)
                return false;

            // 撤退部队无效
            if (unit.order == 部队任务_撤退)
                return false;

            int candidate_count = list_candidate_unit.count;
            if (candidate_count > 4)
                return false;

            uint8 unit_deploy_type = 0;
            uint8 deploy_target = 255;

            auto scenario_ai_table_unit = pk::get_scenario().ai_table.unit[unit.get_id()];

            unit_deploy_type = scenario_ai_table_unit.deploy_type;// 种类(3:运输，4:建设)
            deploy_target = scenario_ai_table_unit.deploy_target;


            pk::building@ deploy_target_building = pk::get_building(deploy_target);

            if (unit_deploy_type != 部队出征类型_攻击 and unit.order != 部队任务_征服 and unit.order != 部队任务_移动)
                return false;


            pk::building @service_base = pk::get_building(pk::get_service(unit));
            pk::building @target_base = pk::get_building(pk::get_building_id(unit.pos));
            if (pk::is_alive(service_base) and pk::is_alive(target_base) and ai::force_attack_base_troops[unit.get_force_id()][target_base.get_id()] > 10000)
            {
                int unit_id = unit.get_id();
                int service_id = service_base.get_id();
                int target_id = target_base.get_id();
                pk::person @leader = pk::get_person(unit.leader);

                // 攻占敌方据点（近距离交战后周围没有部队时才行动，首次出动时未行动
                bool is_enemy_base = pk::is_enemy(unit, target_base);
                bool is_candidate_base = (candidate_count == 0 or (is_weak_base(target_base) and candidate_count > 0));
                if (is_enemy_base and is_candidate_base and (arr_target_base_id[unit_id] != target_id and arr_target_unit_id[unit_id] != -1))
                {

                    arr_target_base_id[unit_id] = target_id;
                    pk::set_order(unit, 部队任务_攻击, target_base.pos);
                    if (pk::is_in_screen(unit.pos))
                    {
                        string target_name = pk::decode(pk::get_name(target_base));
                        switch (pk::rand(3))
                        {
                            case 0:
                                pk::say(pk::encode(pk::format("向\x1b[2x{}\x1b[0x发起进攻吧", target_name)), leader);
                                break;
                            case 1:
                                pk::say(pk::encode(pk::format("向\x1b[2x{}\x1b[0x突击！", target_name)), leader);
                                break;
                            case 2:
                                pk::say(pk::encode(pk::format("攻击\x1b[2x{}\x1b[0x吧", target_name)), leader);
                                break;
                        }
                    }

                    return true;

                }
            }

            return false;
        }

        //---------------------------------------------------------------------------
        // ----- 己方据点_守城支援
        // 防御部队：移动到周围兵力不足的战斗据点
        bool def_force_base_nearby(pk::unit @unit)
        {
            if (!pk::is_alive(unit))
                return false;
            if (unit.type != 部队类型_战斗)
                return false; // 如果不是战斗部队，则排除
            // 无效的撤退命令
            if (unit.order == 部队任务_撤退)
                return false;
            pk::building @service = pk::get_building(pk::get_service(unit));
            if (!pk::is_alive(service))
                return false;
            int candidate_count = list_candidate_unit.count;
            if (candidate_count > 1)
                return false;
            // 搜索周围的目标据点
            pk::list<pk::building @> list_target_base;
            pk::array<pk::point> arr = pk::get_movable_pos(unit);
            for (int i = 0; i < int(arr.length); i++)
            {
                pk::building @base = pk::get_building(arr[i]);
                if (pk::is_alive(base))
                {
                    if (unit.get_force_id() == base.get_force_id() and pk::enemies_around(base))
                    {
                        if (is_weak_base(base))
                            list_target_base.add(base);

                    }
                }
            }
            if (list_target_base.count == 0)
                return false;
            // 当目标据点占多数时优先排序（城市优先于关口港口，兵力不足据点优先，兵力充足时耐久度不足据点优先）
            list_target_base.sort(function(a, b) {
                bool city_a = (0 <= a.get_id() and a.get_id() < 城市_末);
                bool city_b = (0 <= b.get_id() and b.get_id() < 城市_末);
                if (city_a and !city_b)
                    return true;
                if (!city_a and city_b)
                    return false;
                int troops_a = pk::get_troops(a);
                int troops_b = pk::get_troops(b);
                if (troops_a > 3000 and troops_b > 3000)
                    return (int(a.hp) < int(b.hp));
                return (troops_a < troops_b);
            });
            pk::building @target_base = list_target_base[0];
            pk::person @leader = pk::get_person(unit.leader);
            if (pk::is_alive(target_base) and pk::is_alive(leader))
            {
                string leader_name = pk::decode(pk::get_name(leader));
                string target_name = pk::decode(pk::get_name(target_base));
                int target_id = target_base.get_id();
                int unit_id = unit.get_id();
                int max_atk_range = get_atk_range(unit).second;
                pk::array<int> num_unit_around = count_unit_around(unit, target_base); //[0]近战，[1]远程
                // 移动到友方基地
                if (arr_target_base_id[unit_id] != target_id)
                {
                    // 如果是近战部队，或者是远程部队但周围没有可支援的近战部队
                    if (max_atk_range <= 1 or (max_atk_range > 1 and num_unit_around[0] < 1))
                    {
                        // 保存目标重新设置信息
                        arr_target_base_id[unit_id] = target_id;
                        // 设置友方基地移动
                        pk::set_order(unit, 部队任务_攻击, target_base.pos); // 将 部队任务_移动 改为 部队任务_攻击 ('20.9.13)
                        // 目标变更信息
                        if (pk::is_in_screen(unit.pos))
                        {
                            switch (pk::rand(3))
                            {
                                case 0:
                                    pk::say(pk::encode(pk::format("去支援\x1b[2x{}\x1b[0x吧", target_name)), leader);
                                    break;
                                case 1:
                                    pk::say(pk::encode(pk::format("我部将支援\x1b[2x{}\x1b[0x", target_name)), leader);
                                    break;
                                case 2:
                                    pk::say(pk::encode(pk::format("\x1b[2x{}\x1b[0x需要支援", target_name)), leader);
                                    break;
                            }
                        }
                        if (调试模式)
                            pk::info(pk::format("{} 任务目标:{}", leader_name, target_name));
                        return true;
                    }
                }
            }
            return false;
        }
        // 确认部队周边的姿态力近/间接攻击部队数量
        pk::array<int> count_unit_around(pk::unit @unit, pk::building @target_base)
        {
            pk::array<int> count_unit(2, 0); // [0]근접, [1]간접
            pk::array<pk::point> arr = pk::get_movable_pos(unit, target_base.pos, (unit.attr.stat[部队能力_移动] / 2));
            for (int i = 0; i < int(arr.length); i++)
            {
                pk::unit @unit_t = pk::get_unit(arr[i]);
                if (pk::is_alive(unit_t) and unit_t.type == 部队类型_战斗)
                    if (unit.get_id() != unit_t.get_id() and unit.get_force_id() == unit_t.get_force_id())
                    {
                        if (get_atk_range(unit_t).second > 1)
                            count_unit[1]++;
                        else
                            count_unit[0]++;
                    }
            }
            return count_unit;
        }
        // 判断是否为弱势据点的条件
        bool is_weak_base(pk::building @base)
        {
            if (!pk::is_alive(base))
                return false;
            int base_id = base.get_id();
            if (base_id < 0 or base_id >= 据点_末)
                return false;
            bool is_city = (0 <= base_id and base_id < 城市_末);
            int base_troops = pk::get_troops(base);
            int base_hp = int(base.hp);
            int base_max_hp = int(pk::get_max_hp(base));
            if (base_troops < 500 or base_hp < 700)
                return true;
            else if (!is_city and (base_troops <= 1000 and base_hp <= pk::max(1500, int(base_max_hp * 0.75f))))
                return true;
            else if (!is_city and (base_troops <= 2000 and base_hp <= pk::max(1000, int(base_max_hp * 0.50f))))
                return true;
            else if (is_city and (base_troops <= 3000 and base_hp <= pk::max(2000, int(base_max_hp * 0.50f))))
                return true;
            else if (is_city and (base_troops <= 5000 and base_hp <= pk::max(1500, int(base_max_hp * 0.25f))))
                return true;
            return false;
        }

        //---------------------------------------------------------------------------
        // ----- 交战后进入据点部队时设置超额兵力/兵器部队返回
        // 交战部队：确认当前坐标区域的据点势力：true=远征或援军/false=拦截判断
        bool retreat_exceed_unit(pk::unit @unit)
        {
            if (!pk::is_alive(unit))
                return false;
            // 无效的撤退命令
            if (unit.order == 部队任务_撤退)
                return false;
            int unit_id = unit.get_id();
            int leader_id = unit.leader;
            pk::person @leader = pk::get_person(leader_id);
            string unit_name = pk::decode(pk::get_name(leader));
            int candidate_count = list_candidate_unit.count;
            if (candidate_count > 0)
                return false;
            pk::building @service_base = pk::get_building(pk::get_service(unit));
            pk::building @pos_area_base = pk::get_building(pk::get_building_id(unit.pos));
            if (!pk::is_alive(service_base))
                return false;
            if (!pk::is_alive(pos_area_base))
                return false;
            int service_id = service_base.get_id();
            int pos_area_id = pos_area_base.get_id();
            if (!pk::enemies_around(pos_area_base))
            {
                // 当部队进入据点时，设置部队+据点兵力限制
                bool is_service_base = (service_id == pos_area_id);
                bool is_force_base = (unit.get_force_id() == pos_area_base.get_force_id());
                bool is_exceed_unit = (is_force_base and !is_service_base and check_exceed_unit(pos_area_base, unit, true));
                // 如果超过兵力限制，则撤退到所属据点
                if (is_exceed_unit and (arr_target_base_id[unit_id] == pos_area_id and arr_target_unit_id[unit_id] != -1))
                {
                    // 保存目标重新设置信息
                    arr_target_base_id[unit_id] = service_id;
                    // 返回所属据点
                    pk::set_order(unit, 部队任务_攻击, service_base.pos);
                    // 目标变更信息
                    if (pk::is_in_screen(unit.pos))
                    {
                        string old_order = pk::format("不必执行原目标:\x1b[2x{}\x1b[0x\n", pk::decode(pk::get_name(pos_area_base)));
                        string target_name = pk::decode(pk::get_name(service_base));
                        switch (pk::rand(3))
                        {
                            case 0:
                                pk::say(pk::encode(pk::format("{}向\x1b[2x{}\x1b[0x退却吧", old_order, target_name)), leader);
                                break;
                            case 1:
                                pk::say(pk::encode(pk::format("{}向\x1b[2x{}\x1b[0x返回", old_order, target_name)), leader);
                                break;
                            case 2:
                                pk::say(pk::encode(pk::format("{}转向\x1b[2x{}\x1b[0x", old_order, target_name)), leader);
                                break;
                        }
                    }
                    if (调试模式)
                        pk::info(pk::format("部队返回 目标据点: {}", pk::decode(pk::get_name(service_base))));
                }
            }
            // 查询部队任务信息
            bool is_order_retreat = (unit.order == 部队任务_撤退 or (unit.order == 部队任务_移动 and candidate_count == 0));
            // 当部队任务目标据点兵力超过限度时，退到附近兵力不足的据点
            if (is_order_retreat and unit.target_type == 部队任务对象_据点 and pk::is_valid_base_id(unit.target) and unit.target >= 0 and unit.target < 据点_末)
            {
                pk::building @base_t = (is_order_retreat) ? service_base : pk::get_building(unit.target);
                if (pk::is_alive(base_t) and base_t.get_id() < 据点_末)
                {
                    // 获取目标据点的部队进入时的兵力限制
                    string base_t_name = pk::decode(pk::get_name(base_t));
                    int target_id = base_t.get_id();
                    bool is_in_movable_pos = check_base_in_movable_range(unit, base_t);                // 部队的可移动范围内是否存在目标据点
                    bool is_in_city_area = (pk::get_city_id(base_t.pos) == pk::get_city_id(unit.pos)); // 部队所在位置是否与目标据点处于同一城市区域
                    bool is_force_base = (unit.get_force_id() == base_t.get_force_id());
                    bool is_exceed_unit = (is_force_base and (is_in_city_area or is_in_movable_pos) and check_exceed_unit(base_t, unit, true));
                    if (调试模式)
                        pk::info(pk::format("---{}部队 {}:{}", unit_name, get_order_info(unit.order), base_t_name));
                    // 如果部队超过了兵力限制，则撤退到兵力较少的附近据点
                    if (is_exceed_unit)
                    {
                        // 搜索附近据点的函数
                        int dst_id = get_neighbor_base_retreat(base_t, unit);
                        pk::building @dst_base = pk::get_building(dst_id);
                        if (!pk::is_alive(dst_base))
                            return false;
                        // 保存目标重设信息
                        arr_target_base_id[unit_id] = dst_id;
                        // 重新设置部队任务：移动到新的目标据点
                        pk::set_order(unit, 部队任务_攻击, dst_base.pos);
                        // 目标变更消息
                        if (pk::is_in_screen(unit.pos))
                        {
                            string old_order = pk::format("\x1b[2x{}\x1b[0x负责部队\n", pk::decode(pk::get_name(base_t)));
                            string target_name = pk::decode(pk::get_name(dst_base));
                            switch (pk::rand(3))
                            {
                                case 0:
                                    pk::say(pk::encode(pk::format("{}向\x1b[2x{}\x1b[0x进军吧", old_order, target_name)), leader);
                                    break;
                                case 1:
                                    pk::say(pk::encode(pk::format("{}改为 \x1b[2x{}\x1b[0x", old_order, target_name)), leader);
                                    break;
                                case 2:
                                    pk::say(pk::encode(pk::format("{}目标变更为\x1b[2x{}\x1b[0x", old_order, target_name)), leader);
                                    break;
                            }
                        }
                        if (调试模式)
                            pk::info(pk::format("部队返回目标据点: {}", pk::decode(pk::get_name(dst_base))));
                    }
                }
            }
            return false;
        }

        // 获取附近兵力不足的据点
        pk::building @src_t;
        int get_neighbor_base_retreat(pk::building @src_base, pk::unit @unit)
        {
            if (!pk::is_alive(unit) or !pk::is_alive(src_base))
                return -1;
            int dst_id = -1;
            int best_dst = -1;
            int best_distance = 0;
            int src_id = src_base.get_id();
            pk::list<pk::building @> dst_list;
            @src_t = @src_base;
            pk::force @force = pk::get_force(src_base.get_force_id());
            // 搜索撤退据点
            if (pk::get_city_list(force).count <= 1 and src_id < 城市_末)
                return -1; // 如果是最后一个城市，则无法撤退
            else
            {
                for (int i = 0; i < 据点_末; i++)
                {
                    pk::building @dst = pk::get_building(i);
                    dst_id = dst.get_id();
                    bool is_exceed_unit = check_exceed_unit(dst, unit, true);
                    if (!is_exceed_unit and src_id != dst_id and src_base.get_force_id() == dst.get_force_id())
                    {
                        best_dst = dst_id;
                        dst_list.add(dst); // 添加可撤退的据点列表
                    }
                }
            }
            // 对可撤退的据点列表进行排序（据点距离升序，坐标距离升序）
            if (dst_list.count == 0)
                best_dst = -1;
            else
            {
                dst_list.sort(function(a, b) {
                    int build_dist_a = pk::get_building_distance(a.get_id(), main.src_t.get_id(), a.get_force_id());
                    int build_dist_b = pk::get_building_distance(b.get_id(), main.src_t.get_id(), b.get_force_id());
                    int pos_dist_a = pk::get_distance(a.pos, main.src_t.pos);
                    int pos_dist_b = pk::get_distance(b.pos, main.src_t.pos);
                    if (build_dist_a != build_dist_b)
                        return (build_dist_a < build_dist_b);
                    return (pos_dist_a < pos_dist_b);
                });
                best_dst = dst_list[0].get_id();
            }
            return best_dst;
        }

        // 判断据点+部队兵力/兵器是否超过限度
        bool check_exceed_unit(pk::building @base, pk::unit @unit, bool isforce = true)
        {
            if (!pk::is_alive(base) or !pk::is_alive(unit))
                return false;
            if (base.get_id() >= 据点_末)
                return false;
            if (isforce and base.get_force_id() != unit.get_force_id())
                return false;
            if (!isforce and !pk::is_enemy(base, unit))
                return false;
            float exceed_limit = pk::max(0.0f, pk::min(1.0f, 进入部队_超过限度标准));
            float weapon_ignore = pk::max(0.0f, pk::min(1.0f, 进入部队_兵器超过_据点兵力标准));
            bool is_ignore = (float(pk::get_troops(base)) / float(pk::get_max_troops(base)) <= weapon_ignore);
            bool is_exceed_troops = false;
            bool is_exceed_weapon = false;
            if (unit.type == 部队类型_战斗)
            {

                int base_limit = int(float(pk::get_max_troops(base)) * exceed_limit);
                int exceed_troops = pk::max(0, ((pk::get_troops(base) + unit.troops) - base_limit));
                is_exceed_troops = (exceed_troops > 0);


                int gnd_wpn_id = pk::get_ground_weapon_id(unit);
                int sea_wpn_id = pk::get_sea_weapon_id(unit);
                int unit_gnd_wpn_amt = (is_siege_weapon(gnd_wpn_id)) ? 1 : unit.troops;
                int unit_sea_wpn_amt = (sea_wpn_id == 兵器_走舸) ? 0 : 1;
                int base_gnd_wpn_amt = pk::get_weapon_amount(base, gnd_wpn_id);
                int base_sea_wpn_amt = pk::get_weapon_amount(base, sea_wpn_id);
                int exceed_gnd_wpn_amt = pk::max(0, (base_gnd_wpn_amt + unit_gnd_wpn_amt) - int(float(pk::get_max_weapon_amount(base, gnd_wpn_id)) * exceed_limit));
                int exceed_sea_wpn_amt = pk::max(0, (base_sea_wpn_amt + unit_sea_wpn_amt) - int(float(pk::get_max_weapon_amount(base, sea_wpn_id)) * exceed_limit));
                is_exceed_weapon = (exceed_gnd_wpn_amt > 0 or exceed_sea_wpn_amt > 0);

            }
            else if (unit.type == 部队类型_运输)
            {

                int exceed_troops = pk::max(0, ((pk::get_troops(base) + unit.troops) - pk::get_max_troops(base)));
                is_exceed_troops = (exceed_troops >= 2000); // 当部队兵力超过2000时


                pk::array<int> arr_exceed_wpn_amt(兵器_末, 0);
                for (int i = 0; i < 兵器_末; i++)
                {
                    if (!is_exceed_weapon and !is_ignore)
                    {
                        int unit_wpn_amt = unit.stock[i].amount;
                        int base_wpn_amt = pk::get_weapon_amount(base, i);
                        arr_exceed_wpn_amt[i] = pk::max(0, (unit_wpn_amt + unit_wpn_amt) - int(float(pk::get_max_weapon_amount(base, i)) * exceed_limit));
                        if (arr_exceed_wpn_amt[i] >= ((is_siege_weapon(i) or is_ship_weapon(i)) ? 1 : 2000))
                            is_exceed_weapon = true; // 当攻城/船舰兵器数量超过1或战斗兵器数量超过2000时

                    }
                }
            }

            if (调试模式)
            {
                string unit_name = pk::decode(pk::get_name(pk::get_person(unit.leader)));
                string base_name = pk::decode(pk::get_name(base));
                if (is_exceed_troops or is_exceed_weapon)
                    pk::info(pk::format("---{}/{}进入导致库存超额", base_name, unit_name));
            }
            bool is_exceed_unit = (is_exceed_troops or is_exceed_weapon);
            return is_exceed_unit;
        }
        // 判断目标据点是否在部队的可移动范围内
        bool check_base_in_movable_range(pk::unit @unit, pk::building @base)
        {
            if (!pk::is_alive(unit) or !pk::is_alive(base))
                return false;
            pk::array<pk::point> arr_range = pk::get_movable_pos(unit);
            for (int i = 0; i < int(arr_range.length); i++)
            {
                if (base.pos == arr_range[i])
                    return true;
            }
            return false;
        }

        bool is_siege_weapon(int weapon_id) { return (兵器_冲车 <= weapon_id and weapon_id <= 兵器_木兽); }
        bool is_ship_weapon(int weapon_id) { return (兵器_楼船 == weapon_id or weapon_id == 兵器_斗舰); }

        //---------------------------------------------------------------------------

        // 判断是否为有效的部队
        bool check_valid_unit(pk::unit @unit_t)
        {
            if (!pk::is_alive(unit_t))
                return false;
            if (unit_t.type != 部队类型_战斗)
                return false; // 排除运输部队
            int force_id = unit_t.get_force_id();
            pk::force @force = pk::get_force(force_id);
            if (!pk::is_alive(force) or !pk::is_normal_force(force_id))
                return false; // 检查所属势力
            if (!pk::is_alive(pk::get_building(pk::get_service(unit_t))))
                return false; // 排除无法确定所属据点的部队
            int leader_id = unit_t.leader;
            if ((leader_id >= 670 and leader_id < 800) or (leader_id >= 1000 and leader_id < 1100))
                return false;
            return true;
        }

        // 势力条件判断函数
        bool check_force_option(pk::unit @unit_t)
        {
            // 不适用于玩家军团（因为会忽略玩家的任务指定而重新设置目标）
            if (!pk::is_alive(unit_t))
                return false;
            if (pk::is_player_controlled(unit_t))
            {
                if (部队目标变更_适用玩家军团)
                    return true;
                else
                    return false;
            }
            // 0: 适用于电脑AI和玩家_授权军团，1: 仅适用于玩家_授权军团，2: 仅适用于电脑AI，3: 全部不适用
            if (部队目标变更_势力条件 == 0 and !pk::is_player_controlled(unit_t))
                return true;
            else if (部队目标变更_势力条件 == 1 and unit_t.is_player() and !pk::is_player_controlled(unit_t))
                return true;
            else if (部队目标变更_势力条件 == 2 and !unit_t.is_player())
                return true;
            else if (部队目标变更_势力条件 == 3)
                return false;
            return false;
        }
        //---------------------------------------------------------------------------
        // 获取部队的攻击最小和最大射程函数-根据可用战法的设置条件进行计算（'20.9.13)
        pk::int_int get_atk_range(pk::unit @unit)
        {
            pk::int_int atk_range = pk::int_int(1, 1);
            if (!pk::is_alive(unit) or unit.weapon == 兵器_剑)
                return atk_range;
            int weapon_id = unit.weapon;
            if (weapon_id < 0)
                pk::trace(pk::format("{},兵装{},", pk::decode(pk::get_name(unit), weapon_id)));

            pk::equipment @epq = pk::get_equipment(unit.weapon);
            string eqp_name = pk::decode(pk::get_name(epq));
            string info = pk::format("{}", eqp_name);
            int min_range = 5;
            int max_range = 1;
            for (int j = 0; j < 可用战法_末; j++)
            {
                if (epq.tactics[j])
                {
                    pk::tactics @tts = pk::get_tactics(j);
                    string tts_name = pk::decode(pk::get_name(tts));
                    info += pk::format(" {}({},{})", tts_name, tts.min_range, tts.max_range);
                    min_range = pk::min(min_range, tts.min_range);
                    max_range = pk::max(max_range, tts.max_range);
                }
            }
            if (weapon_id == 兵器_弩 and unit.has_tech(技巧_强弩))
                max_range += 1;
            if (weapon_id == 兵器_战马 and (unit.has_tech(技巧_骑射) or unit.has_skill(特技_白马)))
                max_range = pk::max(2, max_range);
            if ((weapon_id == 兵器_井阑 or weapon_id == 兵器_投石) and unit.has_skill(特技_射程))
                max_range += 1;
            atk_range = pk::int_int(min_range, max_range);
            info += pk::format(": 最小({}),最大({})", min_range, max_range);
            // if (调试模式) pk::info(info);
            return atk_range;
        }

        // 获取部队的最大攻击射程函数
        int get_max_atk_range(pk::unit @unit)
        {
            if (!pk::is_alive(unit))
                return 1;
            int weapon_id = unit.weapon;
            int max_range = 0;
            if (weapon_id == 兵器_弩)
                max_range = (unit.has_tech(技巧_强弩)) ? 3 : 2;
            else if (weapon_id == 兵器_战马)
                max_range = (unit.has_tech(技巧_骑射) or unit.has_skill(特技_白马)) ? 2 : 1;
            else if (weapon_id == 兵器_井阑)
                max_range = ((unit.has_skill(特技_射程)) ? 1 : 0) + (pk::get_tactics(战法_攻城火矢).max_range);
            else if (weapon_id == 兵器_投石)
                max_range = ((unit.has_skill(特技_射程)) ? 1 : 0) + (pk::get_tactics(战法_攻城投石).max_range);
            else if (weapon_id >= 兵器_走舸)
                max_range = 2;
            else
                max_range = 1; // 剑, 枪, 极, 兵器等
            return max_range;
        }

        //---------------------------------------------------------------------------
        //---------------------------------------------------------------------------

        int get_weapon_type(int weapon_id)
        {
            int weapon_type = -1;
            if (weapon_id == 兵器_剑)
                weapon_type = 0;
            else if (weapon_id >= 兵器_枪 and weapon_id <= 兵器_战马)
                weapon_type = 1;
            else if (weapon_id == 兵器_冲车 or weapon_id == 兵器_木兽)
                weapon_type = 2;
            else if (weapon_id >= 兵器_井阑 or weapon_id == 兵器_投石)
                weapon_type = 3;
            else if (weapon_id == 兵器_走舸)
                weapon_type = 4;
            else if (weapon_id > 兵器_走舸)
                weapon_type = 5;

            return weapon_type;
        }

        string get_weapon_name(int weapon_id)
        {
            string weapon_name;
            switch (weapon_id)
            {
                case 兵器_剑:
                    weapon_name = "剑兵";
                    break;
                case 兵器_枪:
                    weapon_name = "枪兵";
                    break;
                case 兵器_戟:
                    weapon_name = "戟兵";
                    break;
                case 兵器_弩:
                    weapon_name = "弓兵";
                    break;
                case 兵器_战马:
                    weapon_name = "骑兵";
                    break;
                case 兵器_冲车:
                    weapon_name = "冲车";
                    break;
                case 兵器_井阑:
                    weapon_name = "井栏";
                    break;
                case 兵器_投石:
                    weapon_name = "投石";
                    break;
                case 兵器_木兽:
                    weapon_name = "木兽";
                    break;
                case 兵器_走舸:
                    weapon_name = "走舸";
                    break;
                case 兵器_楼船:
                    weapon_name = "楼船";
                    break;
                case 兵器_斗舰:
                    weapon_name = "斗舰";
                    break;
                default:
                    weapon_name = "??";
                    break;
            }
            return weapon_name;
        }

        string get_tekisei_name(int tekisei)
        {
            string tekisei_name;
            switch (tekisei)
            {
                case 适性_C:
                    tekisei_name = "C";
                    break;
                case 适性_B:
                    tekisei_name = "B";
                    break;
                case 适性_A:
                    tekisei_name = "A";
                    break;
                case 适性_S:
                    tekisei_name = "S";
                    break;
                default:
                    tekisei_name = "↑";
                    break;
            }
            return tekisei_name;
        }
        // 获取兵种颜色函数
        string get_heishu_color(int weapon_id)
        {
            string text_color;
            float weight = main.heishu_weight[pk::equipment_id_to_heishu(weapon_id)];
            if (weapon_id == 兵器_剑)
                text_color = "\x1b[2x"; // 绿色
            else if (weight == heishu_null)
                text_color = "\x1b[29x"; // 红色
            else if (weight == heishu_weak)
                text_color = "\x1b[16x"; // 橙色
            else if (weight == heishu_normal)
                text_color = "\x1b[17x"; // 黄色
            else if (weight == heishu_strong)
                text_color = "\x1b[2x"; // 绿色
            else
                text_color = "\x1b[0x"; // 白色
            return text_color;
        }

        //---------------------------------------------------------------------------

        void clear_target_info()
        {
            for (int i = 0; i < 部队_末; i++)
            {
                arr_target_unit_id[i] = -1;
                arr_target_base_id[i] = -1;
            }
        }

        //---------------------------------------------------------------------------------------

        string get_order_info(int order)
        {
            string name;
            switch (order)
            {
                case 0:
                    name = "部队任务_待命";
                    break;
                case 1:
                    name = "部队任务_移动";
                    break;
                case 2:
                    name = "部队任务_设置";
                    break;
                case 3:
                    name = "部队任务_攻击";
                    break;
                case 4:
                    name = "部队任务_撤退";
                    break;
                case 5:
                    name = "部队任务_拦截";
                    break;
                case 6:
                    name = "部队任务_护卫";
                    break;
                case 7:
                    name = "部队任务_攻城";
                    break;
                case 8:
                    name = "部队任务_修复";
                    break;
                case 9:
                    name = "部队任务_征服";
                    break;
                case 10:
                    name = "部队任务_补给";
                    break;
                case 11:
                    name = "部队任务_歼灭";
                    break;
                case 12:
                    name = "部队任务_追随";
                    break;
                case 13:
                    name = "部队任务_末";
                    break;
                default:
                    name = "部队任务_无";
                    break;
            }

            return name;
        }

    }

    Main main;
}
